/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lcw.library.imagepicker.ability;

import com.lcw.library.imagepicker.ImagePicker;
import com.lcw.library.imagepicker.ResourceTable;
import com.lcw.library.imagepicker.adapter.ImageFoldersItemProvider;
import com.lcw.library.imagepicker.data.MediaFile;
import com.lcw.library.imagepicker.data.MediaFolder;
import com.lcw.library.imagepicker.executors.CommonExecutor;
import com.lcw.library.imagepicker.layouthelper.BaseLayoutHelper;
import com.lcw.library.imagepicker.layouthelper.DelegateAdapter;
import com.lcw.library.imagepicker.layouthelper.GridLayoutHelper;
import com.lcw.library.imagepicker.layouthelper.VirtualLayoutManager;
import com.lcw.library.imagepicker.listener.MediaLoadCallback;
import com.lcw.library.imagepicker.manager.ConfigManager;
import com.lcw.library.imagepicker.manager.SelectionManager;
import com.lcw.library.imagepicker.task.ImageLoadTask;
import com.lcw.library.imagepicker.task.MediaLoadTask;
import com.lcw.library.imagepicker.task.VideoLoadTask;
import com.lcw.library.imagepicker.utils.TextUtils;
import com.lcw.library.imagepicker.utils.TConstant;
import com.lcw.library.imagepicker.utils.ResUtil;
import com.lcw.library.imagepicker.utils.Utils;
import com.lcw.library.imagepicker.utils.DataUtil;
import com.lcw.library.imagepicker.view.ImageFolderPopupWindow;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Text;
import ohos.agp.components.ListContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.BaseDialog;
import ohos.agp.window.service.WindowManager;
import ohos.bundle.IBundleManager;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.rpc.RemoteException;
import ohos.security.SystemPermission;
import ohos.utils.net.Uri;

import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
import java.util.LinkedList;
import java.util.Arrays;

import static ohos.bundle.IBundleManager.PERMISSION_GRANTED;

public class ImagePickerAbility extends BaseAbility implements VirtualLayoutManager.OnItemClickListener, ImageFoldersItemProvider.OnImageFolderChangeListener {
    private String mTitle;
    private boolean isShowCamera, isShowImage, isShowVideo, isSingleType, isShowTime;
    private int mMaxCount;
    private Text mTvCommit, mTvImageTime, mTvImageFolders;
    private ListContainer mMainImagesContainer;
    private ImageFolderPopupWindow mImageFolderPopupWindow;
    private DirectionalLayout mProgressLayout;
    private List<MediaFile> mMediaFileList;
    private List<MediaFolder> mMediaFolderList;
    private static final int LIGHT_OFF = 0, LIGHT_ON = 1, NO_POSITION = -2;
    private EventHandler mMyHandler = new EventHandler(EventRunner.create());
    private DelegateAdapter mDelegateAdapter;
    private VirtualLayoutManager mVirtualLayoutManager;

    private Runnable mHideRunnable = new Runnable() {
        @Override
        public void run() {
            hideImageTime();
        }
    };

    @Override
    protected int bindLayout() {
        return ResourceTable.Layout_ability_imagepicker;
    }

    @Override
    protected void initConfig() {
        mTitle = ConfigManager.getInstance().getTitle();
        isShowCamera = ConfigManager.getInstance().isShowCamera();
        isShowImage = ConfigManager.getInstance().isShowImage();
        isShowVideo = ConfigManager.getInstance().isShowVideo();
        isSingleType = ConfigManager.getInstance().isSingleType();
        mMaxCount = ConfigManager.getInstance().getMaxCount();
        SelectionManager.getInstance().setMaxCount(mMaxCount);

        //Load History Selection Record
        List<String> imagePaths = ConfigManager.getInstance().getImagePaths();
        if (imagePaths != null && !imagePaths.isEmpty()) {
            SelectionManager.getInstance().addImagePathsToSelectList(imagePaths);
        }
        super.initConfig();
    }

    @Override
    protected void initView() {
        mProgressLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_progress_layout);
        mProgressLayout.setVisibility(Component.VISIBLE);
        Text tvTitle = (Text) findComponentById(ResourceTable.Id_tv_actionBar_title);
        if (TextUtils.isEmpty(mTitle)) {
            tvTitle.setText(ResUtil.getString(this, ResourceTable.String_image_picker));
        } else {
            tvTitle.setText(mTitle);
        }
        mTvCommit = (Text) findComponentById(ResourceTable.Id_tv_actionBar_commit);
        mTvImageTime = (Text) findComponentById(ResourceTable.Id_tv_image_time);
        mTvImageFolders = (Text) findComponentById(ResourceTable.Id_tv_main_imageFolders);
        mMainImagesContainer = (ListContainer) findComponentById(ResourceTable.Id_lc_main_images);

        mMediaFileList = new ArrayList<>();
    }

    @Override
    protected void initListener() {
        findComponentById(ResourceTable.Id_iv_actionBar_back).setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component v) {
                setResult(TConstant.RESULT_CANCELED, new Intent());
                terminateAbility();
            }
        });

        mTvCommit.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component v) {
                commitSelection();
            }
        });

        mTvImageFolders.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component view) {
                if (mImageFolderPopupWindow != null) {
                    setLightMode(LIGHT_OFF);
                    mImageFolderPopupWindow.showOnCertainPosition(LayoutAlignment.BOTTOM, 20, 20);
                }
            }
        });

        mMainImagesContainer.setScrolledListener(new Component.ScrolledListener() {
            @Override
            public void onContentScrolled(Component component, int i, int i1, int i2, int i3) {
                updateImageTime();
            }
        });
    }

    private void commitSelection() {
        ArrayList<String> list = new ArrayList<>(SelectionManager.getInstance().getSelectPaths());
        Intent intent = new Intent();
        intent.setStringArrayListParam(ImagePicker.EXTRA_SELECT_IMAGES, list);
        setResult(TConstant.RESULT_OK, intent);
        SelectionManager.getInstance().removeAll();
        terminateAbility();
    }

    private void updateImageTime() {
        int position = mMainImagesContainer.getFirstVisibleItemPosition();
        if (position != NO_POSITION) {
            MediaFile mediaFile = mVirtualLayoutManager.getMediaFile(position);
            if (mediaFile != null) {
                if (mTvImageTime.getVisibility() != Component.VISIBLE) {
                    mTvImageTime.setVisibility(Component.VISIBLE);
                }
                String time = Utils.getImageTime(mediaFile.getDateTaken());
                mTvImageTime.setText(time);
                showImageTime();
                mMyHandler.removeTask(mHideRunnable);
                mMyHandler.postTask(mHideRunnable, 1500);
            }
        }
    }

    private void hideImageTime() {
        if (isShowTime) {
            isShowTime = false;
        }
    }

    /**
     * 显示时间
     */
    private void showImageTime() {
        if (!isShowTime) {
            isShowTime = true;
        }
    }

    private void setLightMode(int lightMode) {
        Optional<WindowManager.LayoutConfig> layoutParams = getWindow().getLayoutConfig();
        if (layoutParams.isPresent()) {
            switch (lightMode) {
                case LIGHT_OFF:
                    layoutParams.get().alpha = 0.7f;
                    break;
                case LIGHT_ON:
                    layoutParams.get().alpha = 1.0f;
                    break;
            }
        }
        getWindow().setLayoutConfig(layoutParams.get());
    }

    @Override
    protected void getData() {
        List<String> permissions = new LinkedList<>(Arrays.asList(SystemPermission.WRITE_USER_STORAGE,
                SystemPermission.READ_USER_STORAGE, SystemPermission.CAMERA));
        permissions.removeIf(
                permission -> verifySelfPermission(permission) == PERMISSION_GRANTED || !canRequestPermission(permission));

        if (!permissions.isEmpty()) {
            requestPermissionsFromUser(permissions.toArray(new String[permissions.size()]), TConstant.REQUEST_PERMISSION_CAMERA_CODE);
        } else {
            startScannerTask();
        }
    }

    private void startScannerTask() {
        Runnable mediaLoadTask = null;
        if (isShowImage && isShowVideo) {
            mediaLoadTask = new MediaLoadTask(this, new MediaLoader());
        }

        if (!isShowImage && isShowVideo) {
            mediaLoadTask = new VideoLoadTask(this, new MediaLoader());
        }

        if (isShowImage && !isShowVideo) {
            mediaLoadTask = new ImageLoadTask(this, new MediaLoader());
        }

        if (mediaLoadTask == null) {
            mediaLoadTask = new MediaLoadTask(this, new MediaLoader());
        }

        CommonExecutor.getInstance().execute(mediaLoadTask);
    }

    class MediaLoader implements MediaLoadCallback {

        @Override
        public void loadMediaSuccess(final List<MediaFolder> mediaFolderList) {
            getUITaskDispatcher().asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    if (!mediaFolderList.isEmpty()) {
                        mMediaFileList.addAll(mediaFolderList.get(0).getMediaFileList());
                        mMaxCount = mMediaFileList.size();
                        SelectionManager.getInstance().setMaxCount(mMaxCount);
                        prepareGridView();

                        mMediaFolderList = new ArrayList<>(mediaFolderList);
                        mImageFolderPopupWindow = new ImageFolderPopupWindow(ImagePickerAbility.this, mMediaFolderList);
                        mImageFolderPopupWindow.getFolderProvider().setOnImageFolderChangeListener(ImagePickerAbility.this);

                        mImageFolderPopupWindow.setDialogListener(new BaseDialog.DialogListener() {
                            @Override
                            public boolean isTouchOutside() {
                                setLightMode(LIGHT_ON);
                                mImageFolderPopupWindow.destroy();
                                return false;
                            }
                        });
                        updateCommitButton();
                    } else {
                        prepareGridView();
                    }
                    mProgressLayout.setVisibility(Component.HIDE);
                }
            });
        }
    }

    private void prepareGridView() {
        mVirtualLayoutManager = new VirtualLayoutManager(ImagePickerAbility.this, mMediaFileList);
        mVirtualLayoutManager.setOnItemClickListener(ImagePickerAbility.this);
        List<DelegateAdapter.Adapter> adapterList = new ArrayList<>();
        int size = mMediaFileList.size() + 1; //10 (9 images & 1 camera)
        adapterList.add(new SubAdapter(new GridLayoutHelper(TConstant.GRID_SPAN_COUNT, size, null, TConstant.GRID_SPAN_HEIGHT)));
        mDelegateAdapter = new DelegateAdapter(mVirtualLayoutManager);
        mDelegateAdapter.addAdapters(adapterList);
        mMainImagesContainer.setItemProvider(mDelegateAdapter);
    }

    private void updateCommitButton() {
        int selectCount = SelectionManager.getInstance().getSelectPaths().size();
        if (selectCount == 0) {
            mTvCommit.setEnabled(false);
            mTvCommit.setText(ResUtil.getString(this, ResourceTable.String_confirm));
            return;
        }
        if (selectCount < mMaxCount) {
            mTvCommit.setEnabled(true);
            mTvCommit.setText(String.format(ResUtil.getString(this, ResourceTable.String_confirm_msg), selectCount, mMaxCount));
            return;
        }
        if (selectCount == mMaxCount) {
            mTvCommit.setEnabled(true);
            mTvCommit.setText(String.format(ResUtil.getString(this, ResourceTable.String_confirm_msg), selectCount, mMaxCount));
        }
    }

    private void launchCamera() {
        Operation operationBuilder = new Intent.OperationBuilder()
                .withBundleName(TConstant.ENTRY_APP_BUNDLE_NAME)
                .withAbilityName(TConstant.CAMERA_ABILITY_EXT)
                .build();
        Intent intent = new Intent();
        intent.setOperation(operationBuilder);
        startAbilityForResult(intent, TConstant.RC_PICK_PICTURE_FROM_CAPTURE);
    }

    @Override
    public void onImageFolderChange(Component view, int position) {
        MediaFolder mediaFolder = mMediaFolderList.get(position);
        String folderName = mediaFolder.getFolderName();
        if (!TextUtils.isEmpty(folderName)) {
            mTvImageFolders.setText(folderName);
        }
        mMediaFileList.clear();
        mMediaFileList.addAll(mediaFolder.getMediaFileList());
        mImageFolderPopupWindow.destroy();
    }

    @Override
    public void onMediaClick(Component view, int position) {
        if (isShowCamera) {
            if (position == 0) {
                if (!SelectionManager.getInstance().isCanChoose()) {
                    Utils.showToast(this, String.format(ResUtil.getString(this, ResourceTable.String_select_image_max), mMaxCount));
                    return;
                }
                launchCamera();
                return;
            }
        }

        if (mMediaFileList != null) {
            DataUtil.getInstance().setMediaData(mMediaFileList);
            Operation operationBuilder = new Intent.OperationBuilder()
                    .withBundleName(TConstant.ENTRY_APP_BUNDLE_NAME)
                    .withAbilityName(TConstant.IMAGE_PRE_EXT)
                    .build();
            Intent intent = new Intent();
            intent.setOperation(operationBuilder);
            if (isShowCamera) {
                intent.setParam(ImagePreAbility.IMAGE_POSITION, position - 1);
            } else {
                intent.setParam(ImagePreAbility.IMAGE_POSITION, position);
            }
            startAbilityForResult(intent, TConstant.REQUEST_SELECT_IMAGES_CODE);
        }
    }

    @Override
    public void onMediaCheck(VirtualLayoutManager.ImagePickerViewHolder viewHolder, Component view, int position) {
        if (isShowCamera) {
            if (position == 0) {
                if (!SelectionManager.getInstance().isCanChoose()) {
                    Utils.showToast(this, String.format(ResUtil.getString(this, ResourceTable.String_select_image_max), mMaxCount));
                    return;
                }
                launchCamera();
                return;
            }
        }

        MediaFile mediaFile = mVirtualLayoutManager.getMediaFile(position - 1);
        if (mediaFile != null) {
            String imagePath = mediaFile.getPath();
            if (isSingleType) {
                ArrayList<String> selectPathList = SelectionManager.getInstance().getSelectPaths();
                if (!selectPathList.isEmpty()) {
                    if (!SelectionManager.isCanAddSelectionPaths(imagePath, selectPathList.get(0))) {
                        Utils.showToast(this, ResUtil.getString(this, ResourceTable.String_single_type_choose));
                        return;
                    }
                }
            }
            boolean addSuccess = SelectionManager.getInstance().addImageToSelectList(imagePath);
            if (addSuccess) {
                VirtualLayoutManager.MediaHolder mediaHolder = (VirtualLayoutManager.MediaHolder) viewHolder;
                mVirtualLayoutManager.bindMedia(mediaHolder, mediaFile);
                mDelegateAdapter.notifyDataSetItemChanged(position);
            } else {
                Utils.showToast(this, String.format(ResUtil.getString(this, ResourceTable.String_select_image_max), mMaxCount));
            }
        }
        updateCommitButton();
    }

    @Override
    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
        try {
            if (resultCode == TConstant.RESULT_OK) {
                if (requestCode == TConstant.RC_PICK_PICTURE_FROM_CAPTURE) {
                    Intent intent = new Intent();
                    String filePath = resultData.getStringParam(TConstant.REQUEST_FILE_PATH);
                    intent.setUri(Uri.parse("file://" + filePath));
                    CommonEventManager.publishCommonEvent(new CommonEventData(intent));

                    SelectionManager.getInstance().addImageToSelectList(filePath);
                    ArrayList<String> list = new ArrayList<>(SelectionManager.getInstance().getSelectPaths());
                    intent.setStringArrayListParam(ImagePicker.EXTRA_SELECT_IMAGES, list);
                    setResult(TConstant.RESULT_OK, intent);
                    SelectionManager.getInstance().removeAll();
                    terminateAbility();
                }

                if (requestCode == TConstant.REQUEST_SELECT_IMAGES_CODE) {
                    commitSelection();
                }
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == TConstant.REQUEST_PERMISSION_CAMERA_CODE) {
            if (grantResults.length >= 1) {
                int cameraResult = grantResults[0];
                int sdResult = grantResults[1];
                boolean cameraGranted = cameraResult == IBundleManager.PERMISSION_GRANTED;
                boolean sdGranted = sdResult == IBundleManager.PERMISSION_GRANTED;
                if (cameraGranted && sdGranted) {
                    startScannerTask();
                } else {
                    Utils.showToast(this, ResUtil.getString(this, ResourceTable.String_permission_tip));
                    mProgressLayout.setVisibility(Component.HIDE);
                    terminateAbility();
                }
            }
        }
        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
    }

    private static class SubAdapter extends DelegateAdapter.Adapter {
        private BaseLayoutHelper mLayoutHelper;

        private SubAdapter(BaseLayoutHelper layoutHelper) {
            mLayoutHelper = layoutHelper;
        }

        @Override
        public BaseLayoutHelper onCreateLayoutHelper() {
            mLayoutHelper.layoutId = ResourceTable.Layout_item_listcontainer_image;
            mLayoutHelper.viewId = ResourceTable.Id_iv_item_image;
            return mLayoutHelper;
        }

        @Override
        public int getCount() {
            return 0;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        @Override
        public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
            return null;
        }
    }

    @Override
    protected void onActive() {
//        mImagePickerItemProvider.notifyDataChanged();
        updateCommitButton();
        super.onActive();
    }

    @Override
    public void onBackPressed() {
        setResult(TConstant.RESULT_CANCELED, new Intent());
        super.onBackPressed();
    }

    @Override
    protected void onStop() {
        try {
            ConfigManager.getInstance().getImageLoader().clearMemoryCache();
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.onStop();
    }
}
